iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
Web 3

從 區塊鏈 到 去中心化應用程式(DApp)系列 第 11

區塊鏈建立: 設定區塊與鏈

  • 分享至 

  • xImage
  •  

區塊與鏈

接下來就要透過 Go 實現區塊鏈

專案 GitHub 位置: https://github.com/weiawesome/block-chain_go

在上回 視覺化的區塊鏈

已經大部分實現過基礎區塊及計算的部分

不過在此處會面臨區塊鏈中更仔細的問題
包括交易的細節的內容、計算細節等等

首先列出此次實現的重點

  1. 區塊物件 與 相關方法
    1. 區塊標頭 與 相關方法
    2. 區塊交易 與 相關方法
    3. 區塊元資訊 與 相關方法
  2. 交易物件 與 相關方法
  3. 其餘相關函式

(像是此處就先將 區塊裡的交易上傳的交易 做分離)

區塊物件 與 相關方法

檔案位置: "./block_structure/blockchain/block.go"

物件格式:

type Block struct {
	BlockTop          BlockTop           `json:"blockTop"`
	BlockTransactions []BlockTransaction `json:"blockTransactions"`
	BlockHash         string             `json:"blockHash"`
	BlockMeta         BlockMeta          `json:"blockMeta"`
}
  1. BlockTop (區塊標頭)
    屬性 BlockTop 物件後方實現
  2. BlockTransactions (區塊交易們)
    屬性 List of BlockTransaction 物件後方實現
  3. BlockMeta (區塊元訊息)
    屬性 BlockMeta 主要放置一些訊息進去 物件後方實現

計算MarkleRoot方法:

func (b *Block) ComputeMarkleRoot() {
	var HashList []string
	for _, transaction := range b.BlockTransactions {
		HashList = append(HashList, transaction.TransactionHash)
	}
	for len(HashList) != 1 {
		var tmpHashList []string
		for i := range HashList {
			if i%2 == 0 {
				if i == len(HashList)-1 {
					tmpHashList = append(tmpHashList, utils.HashSHA256(HashList[i]))
				} else {
					tmpHashList = append(tmpHashList, utils.HashSHA256(HashList[i])+utils.HashSHA256(HashList[i+1]))
				}
			}
		}
		HashList = tmpHashList
	}
	b.BlockTop.MarkleRoot = HashList[0]
}

配合上圖作為解釋,(感覺是棵樹對吧(資料結構 哈哈哈
每次循環都是計算下一層的並且取代掉原本的

最後直到長度為1時 此時的值 就是 Markle Root

計算區塊哈希方法:

func (b *Block) ComputeBlockHash() {
	b.BlockHash = utils.HashSHA256(utils.HashSHA256(b.BlockTop.toString()))
}

將區塊標頭的資訊連續哈希兩次便是此區塊的區塊哈希值

檢查區塊難度方法:

func (b *Block) CheckDifficulty() bool {
	for i := int64(0); i < b.BlockTop.Difficulty; i++ {
		if b.BlockHash[i] != '0' {
			return false
		}
	}
	return true
}

檢查 區塊哈希值 的前方0的個數是否大於等於 區塊難度

區塊標頭 與 相關方法

檔案位置: "./block_structure/blockchain/block_top.go"

物件格式:

type BlockTop struct {
	Version      int32  `json:"version"`
	PreviousHash string `json:"previousHash"`
	TimeStamp    int64  `json:"timeStamp"`
	Difficulty   int64  `json:"difficulty"`
	Nonce        uint32 `json:"nonce"`
	MarkleRoot   string `json:"markleRoot"`
}

基本上 可以看到 區塊標頭的物件實現 基本與當初沒什麼差別
不過對於每個值的屬性使用更精確的型態

  1. Version (版本號)
    屬性 使用 int32 用數字代表版本號
  2. Previous (前區塊之哈希)
    屬性 使用 string 用字串顯示哈希值
  3. TimeStamp (時間戳記)
    屬性 使用 int64 用秒級的時間資訊 確保準確度
  4. Difficulty (區塊難度)
    屬性 使用 int64 用數字代表區塊難度
  5. Nonce (隨機數)
    屬性 使用 uint64 用沒分正負的64位元整數 來做為隨機數
  6. MarkleRoot (Markle根)
    屬性 使用 string 用字串顯示MarkleRoot值

轉字串方法:

func (bt BlockTop) ToString() string {
	return string(bt.Version) +
		bt.PreviousHash +
		strconv.FormatInt(bt.TimeStamp, 10) +
		strconv.FormatInt(bt.Difficulty, 10) +
		strconv.FormatUint(uint64(bt.Nonce), 10) +
		bt.MarkleRoot
}

區塊交易 與 相關方法

檔案位置: "./block_structure/blockchain/block_transaction.go"

物件格式:

type BlockTransaction struct {
	From            []From  `json:"from"`
	To              []To    `json:"to"`
	Fee             float64 `json:"fee"`
	TransactionHash string  `json:"transactionHash"`
}

type From struct {
	UTXOHash string
	Index    int
}

type To struct {
	Address string
	Amount  float64
}
  1. From
    交易發起人必須提出它一筆或多筆未花費的紀錄作為此次花費依據
  2. To
    交易接收人可以是一位或多位 提供每位的地址與給予金額
  3. Fee
    給予礦工的小費
  4. TransactionHash
    屬性 string 用來表示該筆的交易哈希

轉為字串方法:

func (bt *BlockTransaction) ToString() (string, error) {
	fromJson, err := json.Marshal(bt.From)
	if err != nil {
		return "", err
	}
	toJson, err := json.Marshal(bt.To)
	if err != nil {
		return "", err
	}
	return string(fromJson) + string(toJson) + strconv.FormatFloat(bt.Fee, 'f', -1, 64), nil
}

區塊元資訊 與 相關方法

檔案位置: "./block_structure/blockchain/block_meta.go"

物件格式:

type BlockMeta struct {
	Content string `json:"content"`
}

基本就是放一些訊息的地方(通常此處都會是空白)
未來有其他附加功能也可以放在此處

交易物件 與 相關方法

檔案位置: "./block_structure/transaction/transaction.go"

物件格式:

type Transaction struct {
	From            []From
	To              []To
	Fee             float64
	Signature       string
	TransactionHash string
	PublicKey       string
}

type From struct {
	UTXOHash string
	Index    int
}

type To struct {
	Address string
	Amount  float64
}

整體格式與上方區塊交易內容差異不大

因此此處僅提出差異內容

  1. PublicKey (公鑰)
    提交交易時 必須提供公鑰 以作為驗證該筆交易合法性
    包括 檢查UTXO是否是屬於本人、簽名合法性
  2. Signature (交易簽名)
    為交易發起者對該筆交易的簽名 但不會放進區塊鏈中

轉為字串方法:

func (t Transaction) ToString() (string, error) {
	fromJson, err := json.Marshal(t.From)
	if err != nil {
		return "", err
	}
	toJson, err := json.Marshal(t.To)
	if err != nil {
		return "", err
	}
	return string(fromJson) + string(toJson) + strconv.FormatFloat(t.Fee, 'f', -1, 64), nil
}

其餘相關函式

哈希函式

檔案位置: "./utils/hash.go"

func HashSHA256(value string) string {
	data := []byte(value)

	hash := sha256.New()
	hash.Write(data)
	hashedData := hash.Sum(nil)
	hashString := hex.EncodeToString(hashedData)

	return hashString
}

交易轉換(交易物件 轉換 區塊交易物件)

檔案位置: "./block_structure/utils/transaction_tools.go"

func ConvertTransaction(transaction transaction.Transaction) blockchain.BlockTransaction {
	var bt blockchain.BlockTransaction
	bt.TransactionHash = transaction.TransactionHash
	bt.Fee = transaction.Fee
	for _, from := range transaction.From {
		bt.From = append(bt.From, blockchain.From{UTXOHash: from.UTXOHash, Index: from.Index})
	}
	for _, to := range transaction.To {
		bt.To = append(bt.To, blockchain.To{Address: to.Address, Amount: to.Amount})
	}
	return bt
}

建立礦工專屬交易

檔案位置: "./block_structure/utils/transaction_tools.go"

func MinerTransaction(Address string) (blockchain.BlockTransaction, error) {
	var bt blockchain.BlockTransaction
	bt.To = append(bt.To, blockchain.To{Address: Address})
	stringValue, err := bt.ToString()
	if err != nil {
		return bt, err
	}
	bt.TransactionHash = utils.HashSHA256(stringValue)
	return bt, nil
}

礦工在撰寫區塊時

在交易內容上
可以將第一筆內容的 To 寫為自己錢包的地址

這樣便可以證明該筆區塊(如果計算完成)的持有權

未來此區塊生成的虛擬貨幣就屬於 該名礦工的

結言

目前總算完成一個關於區塊以及鏈的基本設定

主要是在處理 交易區塊
而這兩項是組成區塊鏈的關鍵元素

希望透過這篇你能理解

  1. 區塊的設計 及 相關方法
  2. 區塊標頭的設計 及 相關方法
  3. 區塊交易的設計 及 相關方法
  4. 區塊元資訊的設計 及 相關方法
  5. 交易的設計 及 相關方法

其實可以感受到這篇代碼非常多。
認為可以先(閱讀)理解一個基礎設計概念。

再透過 GitHub 下載 Source code 比較能輕鬆理解
搭配使用 便更能夠理解 其中原理!

下回預告

經過巧妙的設計
目前區塊及交易的 型態與方法 已經有了基本的塑形

不過區塊鏈儲存資料的地方在哪裡呢?
又是如何的儲存資訊的呢?
著實令人好奇!!!

接下來是時候再來著手 關於資料庫的建立

下回 "區塊鏈建立: 資料庫的建置與規劃"


上一篇
區塊鏈建立: 開始建立區塊鏈
下一篇
區塊鏈建立: 資料庫的建置與規劃
系列文
從 區塊鏈 到 去中心化應用程式(DApp)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言